<?php
class Aliyunsms
{
  private $accessKeyId = "";   #标识用户
  private $accessSecret = "";  #验证用户秘钥
  private $SignName = "";      #短信签名名称
  // private $TemplateCode = "";  #短信模板ID

  public function __construct()
  {
    $this->accessKeyId = ALISMS_KEY_ID;
    $this->accessSecret = ALISMS_KEY_SECRET;
    $this->SignName = ALISMS_SIGNNAME;
    // $this->TemplateCode = ALISMS_TEMPLATE_CODE;
  }

  /**
   * 发送短信接口
   * @param  [type] $mobile [description]
   * @param  [type] $code   [description]
   * @return [type]         [description]
   * 系统参数
   * SignatureMethod    签名方式。取值范围：HMAC-SHA1。
   * SignatureNonce     签名唯一随机数
   * AccessKeyId        访问秘钥ID
   * SignatureVersion   签名算法版本 1.0
   * Timestamp          请求的时间戳
   * Format             返回的语言类型
   *
   * 业务API参数
   * Action             请求的API方法名称
   * Version            API 的版本号  2017-05-25
   * RegionId           API支持的RegionID  cn-hangzhou
   *
   * PhoneNumbers       接收短信的手机号码
   * SignName           短信签名名称
   * TemplateParam      短信模板变量对应的实际值，JSON格式
   * TemplateCode       短信模板ID
   */
  public function  send_sms($mobile, $templateCode = '', $code = [])
  {
    $Timestamp = gmdate("Y-m-d\TH:i:s\Z");

    #系统参数
    $sysdata = [
      'SignatureMethod' => 'HMAC-SHA1',
      'SignatureNonce' => $this->uuid(),
      'AccessKeyId' => $this->accessKeyId,
      'SignatureVersion' => "1.0",
      'Timestamp' => $Timestamp,
      'Format' => 'json',
    ];

    #业务API参数
    $apidata = $this->apidata($mobile, $templateCode, $code);

    #合并参数
    $datas = array_merge($sysdata, $apidata);

    #升序排列
    ksort($datas);

    #拼接加密字符串
    $sortedQueryStringTmp  = "";
    foreach ($datas as $key => $val) {
      $sortedQueryStringTmp  .= "&" . $key . "=" . $this->encode($val);
    }
    $stringToSign = "GET&%2F&" . $this->encode(substr($sortedQueryStringTmp, 1));

    #加密转码
    $sign = base64_encode(hash_hmac("sha1", $stringToSign, $this->accessSecret . "&",true));

    #生成签名
    $signature = $this->encode($sign);

    #拼接请求链接
    $api = 'dysmsapi.aliyuncs.com';
    $url = "https://".$api."/?Signature=".$signature.$sortedQueryStringTmp;

    try {
      $content = $this->curlRuqust($url);
      return json_decode($content, true);
    } catch( \Exception $e) {
      return false;
    }
  }

  /**
   * 业务参数整合
   * @param  [type] $mobile [description]
   * @param  [type] $code   [description]
   * @return [type]         [description]
   */
  public function apidata($mobile, $templateCode, $code = [])
  {
    $apidata = [
      'Action' =>  'SendSms',
      'Version' => '2017-05-25',
      'RegionId' => 'cn-hangzhou',
      'PhoneNumbers' => $mobile,
      'SignName' => $this->SignName,
      // 'TemplateParam' => "{\"code\":\"".$code."\"}",
      'TemplateParam' => !empty($code) ? json_encode($code) : "",
      // 'TemplateCode' => $this->TemplateCode,
      'TemplateCode' => $templateCode,
    ];
    return $apidata;
  }

  /**
    * 阿里云短信对应转码替换
    * @param  [type] $str [description]
    * @return [type]      [description]
    */
  private function encode($str)
  {
    $res = urlencode($str);
    $res = preg_replace("/\+/", "%20", $res);
    $res = preg_replace("/\*/", "%2A", $res);
    $res = preg_replace("/%7E/", "~", $res);
    return $res;
  }

  /**
    * PHP生成 UUID
    * @return [type] [description]
    */
  public function uuid()
  {
    $chars = md5(uniqid(mt_rand(), true));
    $uuid = substr ( $chars, 0, 8 ) . '-'
          . substr ( $chars, 8, 4 ) . '-'
          . substr ( $chars, 12, 4 ) . '-'
          . substr ( $chars, 16, 4 ) . '-'
          . substr ( $chars, 20, 12 );
    return $uuid ;
  }

  /**
    * 对应CURL请求
    * @param  [type] $url [description]
    * @return [type]      [description]
    */
  private function curlRuqust($url)
  {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_TIMEOUT, 5);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
      "x-sdk-client" => "php/2.0.0"
    ));
    if (substr($url, 0, 5) == 'https') {
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    }
    $rtn = curl_exec($ch);
    if ($rtn === false) {
      trigger_error("[CURL_" . curl_errno($ch) . "]: " . curl_error($ch), E_USER_ERROR);
    }
    curl_close($ch);
    return $rtn;
  }
}
